﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Printing;
using System.IO;
using System.Windows.Forms;
using MPMovieCatalog.Configuration;
using MPMovieCatalog.Configuration.Sections;
using MPMovieCatalog.Domain;
using MPMovieCatalog.Service;
using MPMovieCatalog.Util;

namespace MPMovieCatalog.Forms
{
    public partial class ApplicationForm : Form
    {
        public ApplicationForm()
        {
            InitializeComponent();

            ResourceUtils.Refresh();
            foreach (LanguageFile languageFile in ResourceUtils.GetLanguages())
            {
                ToolStripMenuItem menuItem = new ToolStripMenuItem(languageFile.Language);
                menuItem.Click += new EventHandler(ChangeLanguage);
                languageMenuItem.DropDownItems.Add(menuItem);

                if (languageFile.Language == ResourceUtils.GetCurrentLanguage())
                {
                    menuItem.Checked = true;
                }
            }

            string currentTemplateName = TemplateUtils.GetCurrentTemplateName();
            foreach (Template template in TemplateUtils.FindAllTemplates(TemplateType.View, false))
            {
                ToolStripMenuItem menuItem = new ToolStripMenuItem(template.Description);
                menuItem.Tag = template.Name;

                menuItem.Click += new EventHandler(ChangeTemplate);
                templatesMenuItem.DropDownItems.Add(menuItem);

                if (template.Name == currentTemplateName)
                {
                    menuItem.Checked = true;
                }
            }

            UpdateUI();
        }

        private void ApplicationForm_Load(object sender, EventArgs e)
        {
            LoadSettings();
            RefreshList();
        }

        private void exitMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void movieGrid_SelectionChanged(object sender, EventArgs e)
        {
            ShowMovieInfo();
        }

        private void RefreshList()
        {
            if (MovieServiceFactory.IsInitialized)
            {
                IBindingList oldDatasorce = bindingSource.DataSource as IBindingList;
                IBindingList newDatasource = new MovieBindingList(MovieServiceFactory.getMovieService().FindAllMoviesShortInfo());

                bindingSource.DataSource = newDatasource;
                if (oldDatasorce != null && oldDatasorce.IsSorted)
                {
                    newDatasource.ApplySort(oldDatasorce.SortProperty, oldDatasorce.SortDirection);
                }

                movieCountLabel.Text = string.Format(ResourceUtils.GetString("main", 6), bindingSource.Count.ToString());
            }
        }


        private void LoadSettings()
        {
            ConfigurationWrapper configurationWrapper = new ConfigurationWrapper();
            ConnectionSection connectionSection = configurationWrapper.ConnectionSection;
            try
            {
                MovieServiceFactory.Initialize(connectionSection.Host, connectionSection.Port);
            }
            catch
            {
                MessageBox.Show(this, ResourceUtils.GetString("main", 7), ResourceUtils.GetString("common", 0), MessageBoxButtons.OK, MessageBoxIcon.Error);
                bindingSource.DataSource = null;
            }
        }

        private void movieGrid_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == 13)
            {
                EditMovie(sender, e);
            }
        }

        public void AddMovie(object sender, EventArgs e)
        {
            using (EditForm editForm = new EditForm())
            {
                IMovieService movieService = MovieServiceFactory.getMovieService();
                editForm.AvailableGenres = movieService.FindAvailableGenres(0);
                editForm.AvailableActors = movieService.FindAvailableActors(0);
                editForm.Data = new MovieInfo();
                if (editForm.ShowDialog(this) == DialogResult.OK)
                {
                    MovieInfo movieInfo = editForm.Data;
                    movieInfo.Picture = File.Exists(movieInfo.PictureFileName) ? Convert.ToBase64String(File.ReadAllBytes(movieInfo.PictureFileName)) : null;
                    long movieId = movieService.InsertMovieInfo(movieInfo);

                    MovieShortInfo movieShortInfo = new MovieShortInfo();
                    movieShortInfo.Id = movieId;
                    movieShortInfo.Name = movieInfo.Name;

                    bindingSource.Add(movieShortInfo);
                }
            }
        }

        public void EditMovie(object sender, EventArgs e)
        {
            MovieShortInfo movieShortInfo = (MovieShortInfo)bindingSource.Current;

            IMovieService movieService = MovieServiceFactory.getMovieService();
            MovieInfo movieInfo = movieService.FindMovieInfoById(movieShortInfo.Id);
            if (movieInfo != null && movieInfo.Picture != null && movieInfo.Picture != string.Empty)
            {
                movieInfo.PictureFileName = Utils.GetTempFileName();
                File.WriteAllBytes(movieInfo.PictureFileName, Convert.FromBase64String(movieInfo.Picture));
            }

            using (EditForm editForm = new EditForm())
            {
                editForm.AvailableGenres = movieService.FindAvailableGenres(movieShortInfo.Id);
                editForm.AvailableActors = movieService.FindAvailableActors(movieShortInfo.Id);
                editForm.Data = movieInfo;
                if (editForm.ShowDialog(this) == DialogResult.OK)
                {
                    MovieInfo updatedMovieInfo = editForm.Data;
                    bool updatePicture = movieInfo.PictureFileName != updatedMovieInfo.PictureFileName || movieInfo.Name != updatedMovieInfo.Name;
                    updatedMovieInfo.Picture = updatePicture && File.Exists(updatedMovieInfo.PictureFileName) ? Convert.ToBase64String(File.ReadAllBytes(updatedMovieInfo.PictureFileName)) : null;
                    movieService.UpdateMovieInfo(updatedMovieInfo, updatePicture);

                    movieShortInfo.Name = updatedMovieInfo.Name;
                    ShowMovieInfo();
                }
            }
        }

        public void DeleteMovie(object sender, EventArgs e)
        {
            MovieShortInfo movieShortInfo = (MovieShortInfo)bindingSource.Current;
            if (MessageBox.Show(string.Format(ResourceUtils.GetString("main", 8), movieShortInfo.Name), ResourceUtils.GetString("common", 1), MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                MovieServiceFactory.getMovieService().DeleteMovieInfo(movieShortInfo);
                bindingSource.RemoveCurrent();
            }
        }

        public void ChangeSettings(object sender, EventArgs e)
        {
            using (ConfigurationForm settingForm = new ConfigurationForm())
            {
                if (settingForm.ShowDialog() == DialogResult.OK)
                {
                    settingForm.SaveSettings();
                    LoadSettings();
                    RefreshList();
                }
            }
        }

        public void ShowMovieInfo()
        {
            browser.DocumentText = "";

            if (bindingSource.Current == null) return;

            try
            {
                MovieShortInfo movieShortInfo = (MovieShortInfo)bindingSource.Current;
                MovieInfo movieInfo = MovieServiceFactory.getMovieService().FindMovieInfoById(movieShortInfo.Id);

                browser.DocumentText = TemplateUtils.TransformMovie(movieInfo);
            }
            catch
            {
                MessageBox.Show(this, ResourceUtils.GetString("main", 14), ResourceUtils.GetString("common", 0), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void EditMovie(object sender, DataGridViewCellEventArgs e)
        {
            EditMovie(sender, (EventArgs)e);
        }

        private void ApplicationForm_Shown(object sender, EventArgs e)
        {
            ShowMovieInfo();
        }

        private void RefreshList(object sender, EventArgs e)
        {
            RefreshList();
        }

        private void ApplicationForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            MPMovieCatalog.Util.Utils.DeleteTempFiles();
        }

        private void UpdateUI()
        {
            fileMenuItem.Text = ResourceUtils.GetString("main", 0);
            exitMenuItem.Text = ResourceUtils.GetString("main", 1);
            printMenuItem.Text = ResourceUtils.GetString("main", 15);
            exportMenuItem.Text = ResourceUtils.GetString("main", 16);
            exportTextMenuItem.Text = ResourceUtils.GetString("main", 17);
            exportHTMLMenuItem.Text = ResourceUtils.GetString("main", 18);
            exportAMCMenuItem.Text = ResourceUtils.GetString("main", 19);
            toolsMenuItem.Text = ResourceUtils.GetString("main", 2); ;
            languageMenuItem.Text = ResourceUtils.GetString("main", 3); ;
            settingsMenuItem.Text = ResourceUtils.GetString("main", 4); ;
            titleColumn.HeaderText = ResourceUtils.GetString("main", 5); ;
            movieCountLabel.Text = string.Format(ResourceUtils.GetString("main", 6), bindingSource.Count.ToString());

            refreshButton.ToolTipText = ResourceUtils.GetString("main", 12);
            addTtoolButton.ToolTipText = ResourceUtils.GetString("main", 9);
            editToolButton.ToolTipText = ResourceUtils.GetString("main", 10);
            deleteToolButton.ToolTipText = ResourceUtils.GetString("main", 11);
            optionsToolButton.ToolTipText = ResourceUtils.GetString("main", 4);

            addMenuItem.Text = ResourceUtils.GetString("main", 9);
            editMenuItem.Text = ResourceUtils.GetString("main", 10);
            deleteMenuItem.Text = ResourceUtils.GetString("main", 11);
            refreshMenuItem.Text = ResourceUtils.GetString("main", 12);

            templatesMenuItem.Text = ResourceUtils.GetString("main", 13);
        }

        private void ChangeLanguage(object sender, EventArgs e)
        {
            ToolStripMenuItem currentLanguageMenuItem = sender as ToolStripMenuItem;
            if (!currentLanguageMenuItem.Checked)
            {
                ConfigurationWrapper wrapper = new ConfigurationWrapper();
                wrapper.GUISection.Language = currentLanguageMenuItem.Text;
                wrapper.SaveConfiguration();

                foreach (ToolStripMenuItem menuItem in languageMenuItem.DropDownItems)
                {
                    menuItem.Checked = false;
                }
                currentLanguageMenuItem.Checked = true;

                ResourceUtils.Refresh();
                UpdateUI();
                ShowMovieInfo();
            }
        }

        private void ChangeTemplate(object sender, EventArgs e)
        {
            ToolStripMenuItem currentTemplateMenuItem = sender as ToolStripMenuItem;
            if (!currentTemplateMenuItem.Checked)
            {
                ConfigurationWrapper wrapper = new ConfigurationWrapper();
                wrapper.GUISection.Template = currentTemplateMenuItem.Tag as string;
                wrapper.SaveConfiguration();

                foreach (ToolStripMenuItem menuItem in templatesMenuItem.DropDownItems)
                {
                    menuItem.Checked = false;
                }
                currentTemplateMenuItem.Checked = true;

                ShowMovieInfo();
            }
        }

        internal class MovieBindingList : BindingList<MovieShortInfo>
        {
            private ListSortDirection m_sortDirection;

            private PropertyDescriptor m_sortProperty = null;

            private bool m_isSorted = false;

            private Comparison<MovieShortInfo> m_descSorter = new Comparison<MovieShortInfo>(MovieShortInfo.CompareByNameDesc);

            public MovieBindingList(ArrayList movies)
            {
                foreach (MovieShortInfo movie in movies)
                {
                    Add(movie);
                }

                ListChanged += ListChangedHandler;
            }

            protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
            {
                m_sortDirection = direction;
                m_sortProperty = prop;
                m_isSorted = true;

                if (direction == ListSortDirection.Ascending)
                {
                    ((List<MovieShortInfo>)Items).Sort();
                }
                else
                {
                    ((List<MovieShortInfo>)Items).Sort(m_descSorter);
                }

                OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
            }

            protected override void RemoveSortCore()
            {
                m_sortDirection = ListSortDirection.Ascending;
                m_sortProperty = null;
                m_isSorted = false;

                ((List<MovieShortInfo>)Items).Sort();
            }

            protected override bool SupportsSortingCore
            {
                get
                {
                    return true;
                }
            }

            protected override ListSortDirection SortDirectionCore
            {
                get
                {
                    return m_sortDirection;
                }
            }

            protected override PropertyDescriptor SortPropertyCore
            {
                get
                {
                    return m_sortProperty;
                }
            }

            protected override bool IsSortedCore
            {
                get
                {
                    return m_isSorted;
                }
            }

            private void ListChangedHandler(Object sender, ListChangedEventArgs e)
            {
                if (e.ListChangedType == ListChangedType.ItemAdded && m_isSorted)
                {
                    ApplySortCore(m_sortProperty, m_sortDirection);
                }
            }

        }

        private void printMenuItem_Click(object sender, EventArgs e)
        {
            using (PrintForm printForm = new PrintForm())
            {
                ArrayList selectedMovies = new ArrayList();
                foreach (DataGridViewRow row in movieGrid.SelectedRows)
                {
                    selectedMovies.Add(row.DataBoundItem);
                }
                printForm.SelectedMovies = selectedMovies;
                printForm.AllMoviesCount = bindingSource.Count;
                printForm.ShowDialog(this);
            }
        }
    }
}